package controler;

import graphics.engine.RenderEngine;
import graphics.engine.RenderEngineType;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import java.util.Iterator;
import mathematics.geometry.DiskGeometry;
import mathematics.geometry.Geometry;
import settings.Settings;
import utils.AlignedBox3D;
import utils.Point2D;
import utils.Point3D;
import utils.Ray3D;
import utils.Vector3D;
import view.BaseHybridView;
import view.RoomView;

public class MouseControler implements MouseListener, MouseMotionListener, MouseWheelListener{

	private RenderEngine renderEngine;

	private int height;
	
	private Point2D lastPosition;
	private Point2D lastClickedPoint;
	
	private AlignedBox3D zPlan;
	private Lasso lasso;

	private boolean isDraggingLasso;

	private boolean isTranslatingSelection;
	
	public MouseControler(RenderEngine renderEngine)
	{
		this.renderEngine = renderEngine;
		this.lasso = new Lasso();
	    this.zPlan = new AlignedBox3D(new Point3D(-Float.MAX_VALUE, -Float.MAX_VALUE, -0), new Point3D(Float.MAX_VALUE, Float.MAX_VALUE, 0.0f));
	}

	@Override
	public void mouseClicked(MouseEvent event) 
	{
	     
			if(this.renderEngine.getType() == RenderEngineType.Hybrid)
			{
				if(event.getButton() == MouseEvent.BUTTON1)
				{
					lastClickedPoint =  new Point2D(event.getX(), this.height - event.getY());
					Ray3D ray = this.renderEngine.getCamera().getRay(lastClickedPoint);
					
					ArrayList<BaseHybridView> list = this.renderEngine.getView().intersectedNodes(ray);
					
					
					if(list.size() != 0)
					{
						BaseHybridView view = list.get(list.size() - 1);

						if(event.getModifiersEx() == MouseEvent.SHIFT_DOWN_MASK)
						{
							this.renderEngine.getSelectionManager().addRoom(view);
							view.getModel().isSelected = true;
						}
						else
						{
							view.OnClick();
							this.renderEngine.getView().trajectoryesHaveChanged(true);
							this.renderEngine.getSelectionManager().clearRoomSelection();
						}
					}
					else
					{
						this.renderEngine.getSelectionManager().clearRoomSelection();
					}
				}	
				else if ( Settings.isDebbugMode && event.getButton() == MouseEvent.BUTTON3 )
				{
					
				}
			}
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent event) 
	{
		if(event.getButton() == MouseEvent.BUTTON1)
		{
			if( this.renderEngine.getSelectionManager().nodeListIsEmpty() && (event.getModifiersEx() != (MouseEvent.SHIFT_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK)))
			{
				this.renderEngine.getView().clearSelection();
				this.renderEngine.getSelectionManager().clearRoomSelection();
			}
	        this.lastPosition = new Point2D(event.getX(), -event.getY());
		}
	}

	@Override
	public void mouseReleased(MouseEvent arg0) 
	{		
		if(this.isTranslatingSelection && this.renderEngine.getType() == RenderEngineType.Hybrid)
		{
			if(arg0.getModifiersEx() != (MouseEvent.SHIFT_DOWN_MASK))
			{
				this.renderEngine.getView().clearSelection();
				this.renderEngine.getSelectionManager().clearRoomSelection();
			}
		}
		this.isDraggingLasso = false;
		this.isTranslatingSelection = false;

		
		this.getLasso().end();		
	}

	@Override
	public void mouseDragged(MouseEvent event) 
	{
		Point2D currentPosition = new Point2D(event.getX(), - event.getY());
	
		Vector3D vector = new Vector3D(this.lastPosition.x() - currentPosition.x(), this.lastPosition.y() - currentPosition.y(), 0.0f);

		if(event.getModifiersEx() == MouseEvent.BUTTON1_DOWN_MASK
				|| event.getModifiersEx() == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.SHIFT_DOWN_MASK))
		{
			lastClickedPoint =  new Point2D(event.getX(), this.height - event.getY());
		
			if(!this.isDraggingLasso && this.renderEngine.getSelectionManager().getSelectedNodes().size() > 0)
			{
				this.isTranslatingSelection = true;
				Point3D lastPositionProjected = new Point3D();
				Vector3D normal = new Vector3D();
				Ray3D lastPositionRay = this.renderEngine.getCamera().getRay(lastPosition);
				this.zPlan.intersects(lastPositionRay, lastPositionProjected, normal);

				Point3D currentPositionProjected = new Point3D();
				Ray3D currentPositionRay = this.renderEngine.getCamera().getRay(currentPosition);
				this.zPlan.intersects(currentPositionRay, currentPositionProjected, normal);
				
				Vector3D objectTranslationVector = new Vector3D(currentPositionProjected.x() - lastPositionProjected.x() , currentPositionProjected.y() - lastPositionProjected.y() , 0.0f);

				
				/*for(Iterator<BaseHybridView> it = this.renderEngine.getSelectionManager().getSelectedNodes().iterator(); it.hasNext();)
				{
					BaseModel model = it.next().getModel(); 
					model.translate(objectTranslationVector);
				}*/
			}
			else
			{
				Ray3D ray = this.renderEngine.getCamera().getRay(lastClickedPoint);
				this.isDraggingLasso = true;
				Point3D intersection = new Point3D();
				Vector3D normalAtIntersection = new Vector3D();
				
				if(zPlan.intersects(ray, intersection, normalAtIntersection))
				{
					intersection = new Point3D(intersection.x(), intersection.y(), 0);
					getLasso().add( intersection);
				}
				
				this.renderEngine.getSelectionManager().addAllRoom(this.renderEngine.getView().intersectedNodes(this.getLasso()));
				for(Iterator<BaseHybridView> it = this.renderEngine.getSelectionManager().getSelectedNodes().iterator(); it.hasNext();)
				{
					BaseHybridView node = it.next();
					node.getModel().isSelected = true;		
				}
			}
		}
		else if( event.getModifiersEx() == MouseEvent.BUTTON2_DOWN_MASK)
		{
			this.renderEngine.getCamera().orbit(vector);
		}
		else if(event.getModifiersEx() == MouseEvent.BUTTON3_DOWN_MASK)
		{
			this.renderEngine.getCamera().Translate(vector);
		}
		
		lastPosition = currentPosition;	
	}

	@Override
	public void mouseMoved(MouseEvent event) 
	{
		lastPosition =  new Point2D(event.getX(), - event.getY());

		if(this.renderEngine.getView().isInitialized)
		{
			Ray3D ray = this.renderEngine.getCamera().getRay(new Point2D(event.getX(), this.height - event.getY()));
		
			ArrayList<BaseHybridView> list = this.renderEngine.getView().intersectedNodes(ray);
	
			this.renderEngine.getView().clearMouseOver();
			BaseHybridView highlightedView = null;
			if(list.size() != 0)
			{
				highlightedView = ((BaseHybridView)list.get(list.size() - 1));
				highlightedView.OnMouseOver();
			}
			
			Point3D intersection = new Point3D();
			Vector3D normalAtIntersection = new Vector3D();
			if(zPlan.intersects(ray, intersection, normalAtIntersection))
			{
				this.renderEngine.getSelectionManager().clearTargetSelection();
				Geometry selectionDisk = new DiskGeometry(intersection, Settings.TrajectorySelectionRadius);
				if(highlightedView == null)
				{
					//this.renderEngine.getSelectionManager().addAllTargets(this.renderEngine.getView().getIntersectedTrajectories(selectionDisk));
				}
				else
				{
					this.renderEngine.getSelectionManager().addAllTargets( ((RoomView)highlightedView).getIntersectedTrajectories(selectionDisk));
				}
			}
		}	
	}
	
	@Override
	public void mouseWheelMoved(MouseWheelEvent e) {
		if(e.getWheelRotation() < 0)
		{
			this.renderEngine.getCamera().ZoomUp();
		}
		else if ( e.getWheelRotation() > 0 )
		{
			this.renderEngine.getCamera().ZoomDown();
		}
	}
	
	public void Resize(int width, int height)
	{
		this.height = height;
	}

	public Lasso getLasso() {
		return lasso;
	}

	public void setLasso(Lasso lasso) {
		this.lasso = lasso;
	}


}
